#ifndef __SPARSE_MATRIX__
#define __SPARSE_MATRIX__

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <complex.h>

#include <sys/time.h>

struct timezone {
  int tv_sec;
  int tv_usec;
};

/**
 * the number of nnz for each row is stored in the first element
 *  col_idx[n_max_per_row*i], the first nnz is in col_idx[n_max_per_row*i + 1]
 *  we do not check the validaty of row and col, 
 */
/*
void sparse_add_real(int m_per_row, int *col_idx, double *val_nnz, 
		     int row, int col, double val);
*/
/**
 * treat the sparsity pattern from matrix J0 and S0 the row compress
 * storage format is gotten : I,J,S we assume the memory is reserved by
 * calling functions.  for ease of matrix iteration method, the diagnal
 * entries are put at the beginning of each row.
 */
 /*void sparse_compress_real(int m_per_row, int *col_jdx, double *val_nnz, 
			  int *row_ptr, int *col_idx, double *val, int dim);
 */

void sparse_pattern_Aphi(int **row_ptr, int **col_idx, int *nnz,
			int *Element,int *ElementEdge,
			int N_node, int N_edge, int N_element);

void sparse_pattern_nodal(int **row_ptr, int **col_idx, int *nnz,
			  int *Element, int N_node, int N_element);

void sparse_pattern_edge(int **row_ptr, int **col_idx, int *nnz,
			 int *ElementEdge, int N_edge, int N_element);

void sparsity_pattern(int **row_ptr, int **col_idx, int Msize, int *nnz,
		      int *ElementDOF, int N_element, int n_dof_per_elem);

void add_sparse(int *row_ptr, int *col_idx, 
		double complex *val_nnz, 
		int dof_ii, int dof_jj, 
		double complex entry_val);

void apply_Dirichlet(int *row_ptr, int *col_idx,
		     double complex *val_nnz,
		     double complex *val_rhs,
		     int *bnd_flag,
		     double complex *bnd_val,
		     int N_dof);

void assemb_mat(int *row_ptr, int *col_idx, 
		double complex *val_nnz,         // CSR formatted sparse matrix
		double complex *element_matrix,  //  element-wise sparse matrix
		int *ElementDOF, int N_element, int N_dof_per_elem);

void assemb_rhs(double complex *val_rhs, int N_dof,
		double complex *element_rhs,
		int *ElementDOF, int N_element, 
		int N_dof_per_elem);


void cholmod_solver(int *row_ptr, int *col_idx, double complex *val_nnz, 
		    double complex *val_rhs, double complex *val_sol, 
		    int N_dof);

void superLU_solver(int *row_ptr, int *col_idx, double complex *val_nnz, 
		    double complex *val_rhs, double complex *val_sol, 
		    int N_dof);

void output_mat(char *fileName, 
		int *row_ptr, int *col_idx, double complex *val_nnz, 
		double complex *val_rhs, 
		int Msize);

void write_cplin_sys(char *file_name,
		     int *row_ptr, int *col_idx, 
		     double complex *val_nnz, 
		     double complex *rhs,
		     int n_dof);

// add entry to sparse matrix
void add_sparse_int(int *row_ptr, int *col_idx, 
		    int *val_nnz, 
		    int dof_ii, int dof_jj, 
		    int entry_val);

// add entry to sparse matrix
void add_sparse_real(int *row_ptr, int *col_idx, 
		     double *val_nnz, 
		     int dof_ii, int dof_jj, 
		     double entry_val);

void add_sparse_complex(int *row_ptr, int *col_idx, 
		     double complex *val_nnz, 
		     int dof_ii, int dof_jj, 
			double complex entry_val);

double sparse_entry_real(int *row_ptr, int *col_idx, double *val_nnz, int i, int j);

double complex sparse_entry_complex(int *row_ptr, int *col_idx, 
				    double complex *val_nnz, 
				    int i, int j);

int test_symm(int *row_ptr, int *col_idx, int *val_nnz, int Msize);

void write_txt(int *row_ptr, int *col_idx, double complex *val_nnz, int Msize, char* fileName);
void write_txt2(int *col_idx, double complex *val_nnz, int *row_size,
		int Msize, int nz_row, char* fileName);


#endif
